﻿using FluentValidation.AspNetCore;
using Hangfire;
using Hangfire.Redis;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.PlatformAbstractions;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Serialization;
using StackExchange.Redis;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.IO;
using System.Text;
using TL_Cloud.API.Helpers;
using TL_Cloud.Common;
using TL_Cloud.Common.cache;
using TL_Cloud.Core.Services;
using TL_Cloud.Models.BookShop;
using TL_Cloud.RepositoryService.BookShop;
using TL_Cloud.ViewModels.BookShop;

namespace TL_Cloud.API
{
    public class Startup
    {
        public static string DataProtectPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "DataProtect");

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppBookShopContext>(options =>
            {
                options.UseSqlServer(
                    Configuration.GetConnectionString("DefaultConnection"));
            });

            //仓储注册
            services.AddRepositoryRegister();

            services.Configure<FormOptions>(x =>
            {
                x.ValueLengthLimit = int.MaxValue;
                x.MultipartBodyLengthLimit = int.MaxValue; // In case of multipart
            });
            services.AddMvc(opts =>
            {
                opts.ReturnHttpNotAcceptable = true;
                opts.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()); //支持xml

            })
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

            })
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
            .AddFluentValidation();

            //AutoMapped的映射
            services.AddMap();
            //注册验证
            services.AddValidator();

            //注册邮件配置
            //注入方式1
            //var mailConfig = new MailConfig();
            //Configuration.Bind("MailSetting", mailConfig);
            //services.AddSingleton(typeof(MailConfig), mailConfig);

            //注入方式2
            services.Configure<MailConfig>(options =>
            {
                Configuration.Bind("MailSetting", options);
            });
            services.Configure<SmsConfig>(options =>
            {
                Configuration.Bind("SmsSetting", options);
            });
            //注入邮件发送
            services.AddTransient<IMailSender, MailSender>();
            //注入短信发送
            services.AddTransient<ISmsSender, SmsSender>();


            services.AddTransient<ITypeHelperService, TypeHelperService>();

            //为增加排序和重塑数据
            services.AddMappingContainer();

            //注册IUrlHelper
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
            services.AddScoped<IUrlHelper>(factory =>
            {
                var actionContext = factory.GetService<IActionContextAccessor>().ActionContext;
                return new UrlHelper(actionContext);
            });

            //设置允许跨域
            services.AddCors(options => options.AddPolicy("CorsPolicy",
            builder =>
            {
                builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin()
                       .AllowCredentials();
            }));
            #region Jwt认证
            var jwtSettings = new JwtSettings();
            Configuration.Bind("JwtSettings", jwtSettings);

            services.Configure<JwtSettings>(options =>
            {
                Configuration.Bind("JwtSettings", options);
            });

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = jwtSettings.Issuer,
                    ValidAudience = jwtSettings.Audience,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
                };
            });
            #endregion
            //增加api文档的与栏目
            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new Info
                {
                    Version = "v1",
                    Title = "在线书城"
                });
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                var xmlPath = Path.Combine(basePath, "TL_Cloud.API.xml");
                options.IncludeXmlComments(xmlPath);
            });
            //配置数据保护
            services.AddDataProtection()
               //設置有效期
               .SetDefaultKeyLifetime(new TimeSpan(10, 0, 0, 0))
                //设置应用程序唯一标识
                .SetApplicationName("TL_Cloud")
                ////以下是主加密键 在linux下面不支持
                //.ProtectKeysWithDpapi()
                //数据保护文件key的存放路径
                .PersistKeysToFileSystem(new System.IO.DirectoryInfo(DataProtectPath));


            //增加hangfire的redis
            var redisConfig = new RedisConfig();
            Configuration.Bind("RedisSetting", redisConfig);
            ConfigurationOptions configurationOptions = new ConfigurationOptions();
            configurationOptions.Password = redisConfig.Pwd;
            configurationOptions.EndPoints.Add(redisConfig.Host, redisConfig.Port);
            RedisStorageOptions redisStorageOptions = new RedisStorageOptions { Db = redisConfig.Database };

            services.AddHangfire(x => x.UseRedisStorage(ConnectionMultiplexer.Connect(configurationOptions), redisStorageOptions));

            //Redis配置
            services.Configure<RedisConfig>(options =>
            {
                options.Database = redisConfig.Database;
                options.Host = redisConfig.Host;
                options.Port = redisConfig.Port;
                options.Pwd = redisConfig.Pwd;
            });
            //注册 后台的服务
            services.AddSingleton<Microsoft.Extensions.Hosting.IHostedService, HangfireTimeService>();


            //注册redis
            services.AddSingleton<ICache, RedisCache>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            //使用监控每个请求耗费的时间
            app.UseResponseTime();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseHttpsRedirection();
            app.UseCors("CorsPolicy");
            app.UseStaticFiles();
            //把项目当中upload文件夹映射成静态资源文件
            app.UseStaticFiles(new StaticFileOptions
            {
                FileProvider = new PhysicalFileProvider(
                   Path.Combine(env.ContentRootPath, @"upload")),
                RequestPath = new PathString("/upload")
            });
            app.UseAuthentication();
            app.UseHangfireServer();
            app.UseHangfireDashboard();
            //启用中间件服务生成Swagger作为JSON终结点
            app.UseSwagger();
            //启用中间件服务对swagger-ui，指定Swagger JSON终结点
            app.UseSwaggerUI(c =>
            {
                c.SwaggerEndpoint("/swagger/v1/swagger.json", "TL_BookShop V1");
            });

            app.UseMvc();
        }   
    }
}
